/*
 * SpeculationManager.h
 *
 *  Created on: Mar 28, 2012
 *      Author: user
 */

#ifndef SPECULATIONMANAGER_H_
#define SPECULATIONMANAGER_H_

#include <map>
#include <string>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include "SpeculationTask.h"

using namespace std;

//#define VERBOSE 1
//#define LOG 1

#ifndef VERBOSE
#define DEBUG_LOG(...)
#else
#ifndef LOG
#define DEBUG_LOG(args...) printf(args);
#else
#define DEBUG_LOG(args...) printf(args); fprintf(m_log, args); fflush( m_log );
#endif
#endif

class SpeculationManager
{
public:
	~SpeculationManager();

	void setSpeculationGenerator(SpeculationGeneratorFunction gen) { m_speculationGenerator = gen; }

	static SpeculationManager *Instance();

	void setRunningTasks(int tasks) { m_maximumRunningTasks = tasks; }
	void setTotalTasks(int tasks) { m_maximumTasks = tasks; }

	void startSpeculation(SpeculationTask *speculation);
	void commitSpeculation(SpeculationTask *speculation);

	SpeculationTask *getSpeculationTask(string signature);

	void sendCommandToClone( SpeculationTask *clone, int command );
	void recvCommandFromClone( SpeculationTask *clone, int *command );

	void sendToClone( SpeculationTask *clone, int size, const void *data );
	void recvFromClone( SpeculationTask *clone, int size, void *data );

	int getRank() { return m_rank; }
    timeval getStartClock() { return m_startTimeStamp; }

	void killAllSpeculations();

	void run();

protected:

	SpeculationManager(int maxTasks = 0, int maxRunningTasks = 0);

	void killAllSpeculationsButOne(SpeculationTask* s);

	static SpeculationManager *m_instance;

	SpeculationGeneratorFunction	m_speculationGenerator;

	unsigned int m_maximumTasks;
	unsigned int m_maximumRunningTasks;

	map<string,SpeculationTask*> m_tasks;

	int m_rank;

    FILE    *m_log;

    int m_listenSocket;

	timeval m_startTimeStamp;
	timeval m_timeStamp;

};

#define COMMIT(X,Y)	startCommandClock(); \
SpeculationManager* manager = SpeculationManager::Instance(); \
SpeculationTask *speculation = manager->getSpeculationTask( (X) ); \
if(speculation) \
{ \
	speculation->commit(); \
} \
else \
{ \
	Y; \
} \
stopCommandClock( (X) );

#endif /* SPECULATIONMANAGER_H_ */
